import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;

import java.io.*;
import java.util.ArrayList;

public class ModifyInterface {
    public static  String readFromTextFile(String pathname) throws IOException{
        String code="";
        File filename = new File(pathname);
        InputStreamReader reader = new InputStreamReader(new FileInputStream(filename));
        BufferedReader br = new BufferedReader(reader);
        String line = "";
        line = br.readLine();
        while(line != null) {
            code+=line+"\n";
            line = br.readLine();
        }
        return code;
    }
    public static void GenAADL(ArrayList<FuncToAADL> ftlist) throws IOException {
        int count=0;
        String rootPath="H:\\aadl_thread_gen";



        for(FuncToAADL ft:ftlist)
        {
            PrintStream psOld = System.out;
            String aadlPath=rootPath+"\\"+count+".aadl";
            System.out.println(aadlPath);
            File f = new File(aadlPath);
            if(!f.exists()){
                f.createNewFile();
            }
            System.setOut(new PrintStream(f));

            System.out.println("thread "+ft.getName().strip());
            System.out.println("\tfeatures");
            for(String paramName:ft.getParamName())
            {
                System.out.println("\t\t"+paramName+": in data port;");
            }
            System.out.println("\t\t"+ft.getRetType()+":out event data port");
            System.out.println("\tproperties");
            for(int i=0;i<ft.getParamName().size();i++)
            {
                System.out.println("\t\tParam_Property::param_type=>\""+ft.getParamType().get(i)+"\" applies to "+ft.getParamName().get(i)+";");
            }
            System.out.println("\t\tParam_Property::return_type=>\""+ft.getRetType()+"\" applies to "+ft.getRetType()+";");
            System.out.println("end "+ft.getName().strip());
            System.out.println("thread implementation "+ft.getName().strip()+".impl");
            System.out.println("end "+ft.getName().strip()+".impl;");
            count++;
            System.setOut(psOld);
        }

    }
    public static void getParamAndType(StringBuffer sb,FuncToAADL ft)
    {
        ArrayList<String> paramType=new ArrayList<>();
        ArrayList<String> paramName=new ArrayList<>();
        String[] params=sb.toString().split(",");
        if(params.length>0)
        {
            for(String s:params)
            {
                String[] sp=s.split(" ");
                if(sp.length>0)
                {
                    System.out.print("type:");
                    StringBuffer type=new StringBuffer();
                    for(int i=0;i<sp.length-1;i++)
                    {
                        System.out.print(sp[i]+" ");
                        type.append(sp[i]+" ");

                    }
                    paramType.add(type.toString());
                    System.out.println();
                    System.out.println("param:"+sp[sp.length-1]);
                    paramName.add(sp[sp.length-1]);
                }
            }
        }
        ft.setParamName(paramName);
        ft.setParamType(paramType);
    }
    public static void findNameSpace(Tree tree,StringBuffer sb)
    {
        TreeProcessor tp=new TreeProcessor();
        if(!tree.isEmpty()) {
            if(tree.getRootData().equals("qualifiedid")&&tree.getChildCount()==2)
            {//find call function,make it return value
                tree.getChild(0).deleteChilds();
                tree.getChild(0).setRootData("");
                tp.printCodeToSb(tree,sb);

                System.out.println("function name"+sb);
                //System.out.println(sb);
            }


            for(Tree child : tree.getChilds())
            {
                if(child != null)
                {
                    findNameSpace(child,sb);
                }
            }
        }
    }
    public static void findParamList(Tree tree,StringBuffer sb)
    {
        TreeProcessor tp=new TreeProcessor();
        if(!tree.isEmpty()) {
            if (tree.getRootData().equals("parametersandqualifiers") && tree.getChildCount() ==3)
            {//find call function,make it return value
                tp.printParamListToSb(tree.getChild(1), sb);
            }
            for(Tree child : tree.getChilds())
            {
                if(child != null)
                {
                    findParamList(child,sb);
                }
            }
        }
    }
    public static void deleteNameSpace(Tree tree,ArrayList<FuncToAADL> ftlist) throws IOException {
        TreeProcessor tp=new TreeProcessor();
        if(!tree.isEmpty()) {
            if(tree.getRootData().equals("functiondefinition")&&tree.getChildCount()==3)
            {//find call function,make it return value
                StringBuffer sb=new StringBuffer();
                StringBuffer retType=new StringBuffer();
                StringBuffer paramList=new StringBuffer();

                FuncToAADL ft=new FuncToAADL();
                if(tree.getChild(0).getRootData().equals("declspecifierseq"))
                {
                    tp.printCodeToSb(tree.getChild(0),retType);
                    System.out.println("return type:"+retType.toString());
                    ft.setRetType(retType.toString());
                }
                if(tree.getChild(1).getRootData().equals("declarator"))
                {
                    findParamList(tree.getChild(1),paramList);
                    System.out.println("paramList:"+paramList);
                    getParamAndType(paramList,ft);
                    findNameSpace(tree.getChild(1),sb);
                    ft.setName(sb.toString());

                }
                if(tree.getChild(2).getRootData().equals("functionbody"))
                {
                    String rootdir="H:\\aadl_lib\\srl_src";
                    String printPath=rootdir+"\\"+sb.toString().strip()+".cpp";
                    System.out.println(printPath);
                    ft.setCppPath(printPath);
                    PrintStream psOld = System.out;
                    File f = new File(printPath);
                    if(!f.exists()){
                        f.createNewFile();
                    }
                    System.setOut(new PrintStream(f));
                    tp.printCodeToFile(tree);
                    System.setOut(psOld);
                }
                ftlist.add(ft);

            }
            /*if(tree.getRootData().equals("declarator")&&tree.getChildCount()==1)
            {//find call function,make it return value
                if(tree.getChild(0).getChildCount()==1)
                {
                    if(tree.getChild(0).getChild(0).getRootData().equals("noptrdeclarator"))
                    {
                        findNameSpace(tree.getChild(0).getChild(0));
                    }
                }

            }*/


            for(Tree child : tree.getChilds())
            {
                if(child != null)
                {
                    deleteNameSpace(child,ftlist);
                }
            }
        }
    }

    public static void MergeCppFuncs(String loadPath,ArrayList<FuncToAADL> ftlist) throws IOException {
        TreeProcessor tp=new TreeProcessor();
        String code=readFromTextFile(loadPath);

        ANTLRInputStream input = new ANTLRInputStream(code);
        CPP14Lexer lexer = new CPP14Lexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        CPP14Parser parser = new CPP14Parser(tokens);
        CPP14Parser.TranslationunitContext tree = parser.translationunit();

        tree.removeLastChild();
        //System.out.println(tree.getText());
        //visitorTree(tree4,parser4);
        Tree myTree=new Tree(tp.getRuleName(tree,parser));
        tp.convertTree(tree,parser,myTree);

        ArrayList<Tree> funclist=new ArrayList<>();
        tp.getFunctionDefinition(myTree,funclist);


        ArrayList<String> funcNameList=new ArrayList<>();
        for(Tree Func:funclist){

            deleteNameSpace(Func,ftlist);
        }


    }
    public static void main(String[] args) throws IOException {
        ArrayList<FuncToAADL> ftlist=new ArrayList<>();
        MergeCppFuncs("H:\\GIT\\srl_global_planner-master\\src\\srl_global_planner.cpp",ftlist);
        GenAADL(ftlist);
    }
}
